package com.ruoyi.user.task;

import com.ruoyi.system.domain.SpffVideos;
import com.ruoyi.system.mapper.SpffVideosMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 视频推荐缓存更新定时任务
 * 
 * @author xjj
 * @date 2025-09-23
 */
@Component
public class VideoRecommendCacheTask 
{
    @Autowired
    private SpffVideosMapper spffVideosMapper;
    
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    // Redis Key 常量
    private static final String HOT_VIDEOS_KEY = "hot:videos:global";
    private static final String HOT_CATEGORY_PREFIX = "hot:videos:category:";
    private static final String HOT_VIDEOS_HASH_KEY = "hot:videos:hash:global";
    private static final String HOT_CATEGORY_HASH_PREFIX = "hot:videos:hash:category:";
    
    /**
     * 每5分钟更新热门视频榜单缓存
     */
    @Scheduled(fixedRate = 300000) // 5分钟
    public void updateHotVideosCache() {
        try {
            // 1. 更新全站热门榜单
            updateGlobalHotVideos();
            
            // 2. 更新分类热门榜单
            updateCategoryHotVideos();
            
            System.out.println("热门视频缓存更新完成: " + new Date());
        } catch (Exception e) {
            System.err.println("更新热门视频缓存失败: " + e.getMessage());
        }
    }

    /**
     * 更新全站热门视频缓存
     */
    private void updateGlobalHotVideos() {
        Map<String, Object> params = new HashMap<>();
        params.put("type", "global");
        params.put("categoryId", null);
        params.put("offset", 0);
        params.put("limit", 200);
        
        List<SpffVideos> hotVideos = spffVideosMapper.selectHotVideos(params);
        
        if (!hotVideos.isEmpty()) {
            ZSetOperations<Object, Object> zSetOps = redisTemplate.opsForZSet();
            
            // 清除旧缓存
            redisTemplate.delete(HOT_VIDEOS_KEY);
            redisTemplate.delete(HOT_VIDEOS_HASH_KEY);
            
            // 1. ZSet存储排序信息（videoId -> hotScore）
            Map<Object, Double> scoreMap = new HashMap<>();
            // 2. Hash存储完整视频信息（videoId -> video对象）
            Map<Object, Object> videoMap = new HashMap<>();
            
            for (SpffVideos video : hotVideos) {
                double hotScore = calculateHotScore(video);
                scoreMap.put(video.getId(), hotScore);
                videoMap.put(video.getId().toString(), video);
            }
            
            // 批量添加到ZSet（用于排序和分页）
            for (Map.Entry<Object, Double> entry : scoreMap.entrySet()) {
                zSetOps.add(HOT_VIDEOS_KEY, entry.getKey(), entry.getValue());
            }
            
            // 批量添加到Hash（存储完整视频对象）
            if (!videoMap.isEmpty()) {
                redisTemplate.opsForHash().putAll(HOT_VIDEOS_HASH_KEY, videoMap);
            }
            
            // 设置过期时间
            redisTemplate.expire(HOT_VIDEOS_KEY, 600, TimeUnit.SECONDS); // 10分钟过期
            redisTemplate.expire(HOT_VIDEOS_HASH_KEY, 600, TimeUnit.SECONDS);
            
            System.out.println("全站热门视频缓存更新完成，共缓存 " + hotVideos.size() + " 个视频");
        }
    }

    /**
     * 更新分类热门视频缓存
     */
    private void updateCategoryHotVideos() {
        // 获取所有分类
        List<Long> categoryIds = spffVideosMapper.selectAllCategoryIds();
        
        for (Long categoryId : categoryIds) {
            Map<String, Object> params = new HashMap<>();
            params.put("type", "category");
            params.put("categoryId", categoryId);
            params.put("offset", 0);
            params.put("limit", 100);
            
            List<SpffVideos> categoryHotVideos = spffVideosMapper.selectHotVideos(params);
            
            if (!categoryHotVideos.isEmpty()) {
                String zsetKey = HOT_CATEGORY_PREFIX + categoryId;
                String hashKey = HOT_CATEGORY_HASH_PREFIX + categoryId;
                ZSetOperations<Object, Object> zSetOps = redisTemplate.opsForZSet();
                
                // 清除旧缓存
                redisTemplate.delete(zsetKey);
                redisTemplate.delete(hashKey);
                
                // 1. ZSet存储排序信息（videoId -> hotScore）
                Map<Object, Double> scoreMap = new HashMap<>();
                // 2. Hash存储完整视频信息（videoId -> video对象）
                Map<Object, Object> videoMap = new HashMap<>();
                
                for (SpffVideos video : categoryHotVideos) {
                    double hotScore = calculateHotScore(video);
                    scoreMap.put(video.getId(), hotScore);
                    videoMap.put(video.getId().toString(), video);
                }
                
                // 批量添加到ZSet（用于排序和分页）
                for (Map.Entry<Object, Double> entry : scoreMap.entrySet()) {
                    zSetOps.add(zsetKey, entry.getKey(), entry.getValue());
                }
                
                // 批量添加到Hash（存储完整视频对象）
                if (!videoMap.isEmpty()) {
                    redisTemplate.opsForHash().putAll(hashKey, videoMap);
                }
                
                // 设置过期时间
                redisTemplate.expire(zsetKey, 600, TimeUnit.SECONDS);
                redisTemplate.expire(hashKey, 600, TimeUnit.SECONDS);
                
                System.out.println("分类 " + categoryId + " 热门视频缓存更新完成，共缓存 " + categoryHotVideos.size() + " 个视频");
            }
        }
    }

    /**
     * 每小时清理用户推荐缓存
     */
    @Scheduled(fixedRate = 3600000) // 1小时
    public void cleanUserRecommendCache() {
        try {
            // 清理过期的用户推荐ZSet缓存
            String zsetPattern = "recommend:user:*";
            java.util.Set<Object> zsetKeys = redisTemplate.keys(zsetPattern);
            if (zsetKeys != null && !zsetKeys.isEmpty()) {
                redisTemplate.delete(zsetKeys);
            }
            
            // 清理过期的用户推荐Hash缓存
            String hashPattern = "recommend:user:hash:*";
            java.util.Set<Object> hashKeys = redisTemplate.keys(hashPattern);
            if (hashKeys != null && !hashKeys.isEmpty()) {
                redisTemplate.delete(hashKeys);
            }
            
            System.out.println("用户推荐缓存清理完成，ZSet: " + (zsetKeys != null ? zsetKeys.size() : 0) + 
                " 个，Hash: " + (hashKeys != null ? hashKeys.size() : 0) + " 个，时间: " + new java.util.Date());
        } catch (Exception e) {
            System.err.println("清理用户推荐缓存失败: " + e.getMessage());
        }
    }

    /**
     * 每30分钟清理地理位置缓存
     */
    @Scheduled(fixedRate = 1800000) // 30分钟
    public void cleanNearbyVideosCache() {
        try {
            // 清理过期的地理位置ZSet缓存
            String zsetPattern = "nearby:videos:*";
            java.util.Set<Object> zsetKeys = redisTemplate.keys(zsetPattern);
            if (zsetKeys != null && !zsetKeys.isEmpty()) {
                redisTemplate.delete(zsetKeys);
            }
            
            // 清理过期的地理位置Hash缓存
            String hashPattern = "nearby:videos:hash:*";
            java.util.Set<Object> hashKeys = redisTemplate.keys(hashPattern);
            if (hashKeys != null && !hashKeys.isEmpty()) {
                redisTemplate.delete(hashKeys);
            }
            
            System.out.println("地理位置缓存清理完成，ZSet: " + (zsetKeys != null ? zsetKeys.size() : 0) + 
                " 个，Hash: " + (hashKeys != null ? hashKeys.size() : 0) + " 个，时间: " + new java.util.Date());
        } catch (Exception e) {
            System.err.println("清理地理位置缓存失败: " + e.getMessage());
        }
    }

    /**
     * 计算热度得分
     */
    private double calculateHotScore(SpffVideos video) {
        long viewCount = video.getViewCount() != null ? video.getViewCount() : 0;
        long likeCount = video.getLikeCount() != null ? video.getLikeCount() : 0;
        long commentCount = video.getCommentCount() != null ? video.getCommentCount() : 0;
        long shareCount = video.getShareCount() != null ? video.getShareCount() : 0;
        long collectCount = video.getCollectCount() != null ? video.getCollectCount() : 0;
        
        return viewCount * 0.3 + likeCount * 8 + commentCount * 15 + shareCount * 25 + collectCount * 20;
    }
}
